#pragma once
#include <memory>
#include <mutex>
#include <condition_variable>

#include <stdio.h>
#include "spthread.h"

using namespace std;

class ArrayList {
public:
	static const int LAST_INDEX;

	ArrayList(int initCount = 32);
	virtual ~ArrayList();

	int getCount() const;
	int append( void * value );
	const void * getItem( int index ) const;
	void * takeItem( int index );

	void clean();

private:
	ArrayList(ArrayList &);
	ArrayList & operator=(ArrayList &);

	int mMaxCount;
	int mCount;
	void ** mFirst;
};

class CircleQueue {
public:
	CircleQueue(int count = 102400);
	virtual ~CircleQueue();

	void push( void * item );
	void * pop();
	void * top();
	int getLength();

private:
	void ** mEntries;
	unsigned int mHead;
	unsigned int mTail;
	unsigned int mCount;
	unsigned int mMaxCount;
};

template <typename T>
class CircleQueuePtr {
public:
	CircleQueuePtr(int count=102400)
	{
		//printf("CircleQueuePtr\r\n");
		mMaxCount = count+1;
	    mEntries = (shared_ptr<T>*)new shared_ptr<T>[ mMaxCount];
		memset(mEntries,0,sizeof(shared_ptr<T> ) * mMaxCount);
	    mHead = mTail = mCount = 0;
	}
	virtual ~CircleQueuePtr()
	{
		//printf("~CircleQueuePtr\r\n");
		clear();
		delete [] mEntries;
	    mEntries = NULL;
	}

	void push( shared_ptr<T> item )
	{
		if( mCount >= mMaxCount ) {
			int oldSize=mMaxCount;
			int maxcount = ( mMaxCount * 3 ) / 2 + 1;
			shared_ptr<T>* newEntries = (shared_ptr<T>*)new shared_ptr<T>[ maxcount];
			if(newEntries==NULL)
			    return;
			mMaxCount=maxcount;
			memset(newEntries,0,sizeof(shared_ptr<T> ) * maxcount);

			unsigned int headLen = 0, tailLen = 0;
			if( mHead < mTail ) {
				headLen = mTail - mHead;
			} else {
				headLen = mCount - mTail;
				tailLen = mTail;
			}

			memcpy( newEntries, &( mEntries[ mHead ] ), sizeof( shared_ptr<T> ) * headLen );
			if( tailLen ) {
				memcpy( &( newEntries[ headLen ] ), mEntries, sizeof(shared_ptr<T> ) * tailLen );
			}

			mHead = 0;
			mTail = headLen + tailLen;

			memset(mEntries,0,sizeof( shared_ptr<T> ) * oldSize);
			delete [] mEntries ;
			mEntries = newEntries;
		}

		mEntries[ mTail++ ] = item;
		mTail = mTail % mMaxCount;
		mCount++;
	}
	shared_ptr<T> pop()
	{
		shared_ptr<T> ret;

		if( mCount > 0 ) {
			ret = mEntries[ mHead ];
			mEntries[ mHead ].reset();
			mHead++;
			mHead = mHead % mMaxCount;
			mCount--;
		}

		return ret;
	}
	shared_ptr<T> top()
	{
		shared_ptr<T> ret;

		if( mCount > 0 ) {
			ret = mEntries[ mHead ];
		}

		return ret;
		//return mCount > 0 ? mEntries[ mHead ] : NULL;
	}
	int getLength()
	{
		return mCount;
	}
	void clear()
	{
		/*while( mCount > 0 ) {
			mEntries[ mHead ].reset();
			mHead++;
			mHead = mHead % mMaxCount;
			mCount--;
		}*/
	}
private:
	shared_ptr<T>* mEntries;
	unsigned int mHead;
	unsigned int mTail;
	unsigned int mCount;
	unsigned int mMaxCount;
};


class BlockingQueue {
public:
	BlockingQueue();
	virtual ~BlockingQueue();

	// non-blocking
	bool push( void * item );

	// blocking until can pop
	void * pop();

	// non-blocking, if empty then return NULL
	void * top();

	// non-blocking
	int getLength();

	void reserve(int len);

private:
	CircleQueue * mQueue;
	std::mutex mtx;
	std::condition_variable  cond;
};

class SafeQueue {
private:
	const static int MAXCOUNT=999999;
public:
	SafeQueue(int count = 102400);
	virtual ~SafeQueue();

	// non-blocking
	bool push( void * item );

	// blocking until can pop
	void * pop();

	// non-blocking, if empty then return NULL
	void * top();

	// non-blocking
	int getLength();

	void reserve(int len);

private:
	int maxcount;
	CircleQueue * mQueue;
	std::mutex mtx;
	sp_thread_semaphore_t mSem;
};

int strtok( const char * src, int index, char * dest, int len,
		char delimiter = ' ', const char ** next = 0 );

char * strlcpy( char * dest, const char * src, int n );


